<template>
  <q-btn :loading="innerLoading" icon="downloading" no-wrap outline text-color="primary" v-bind="$attrs"
         @click="handleExport">
    <q-tooltip v-if="$attrs.round" class="text-no-wrap" v-bind="$tooltipAttr">
      {{ exportText || $t('ExportList') }}
    </q-tooltip>
    <template v-else>{{ exportText || $t('ExportList') }}</template>
  </q-btn>
</template>

<script setup>
import { i18n, toI18nName } from 'boot/i18n'
import { exportJsonToExcel } from 'components/Global/Tools/ExportUtils'
import { Notify } from 'quasar'
import { awaitGetAPI, awaitPostAPI } from 'src/api'
import { exportedStreamFile, getTypeof } from 'src/utils/utils'
import { computed, ref, watch } from 'vue'
import { useRoute } from 'vue-router'

const props = defineProps({
  data: Array, merges: Array, columns: Array, loading: Boolean, fileName: String, exportUrl: String, isStream: Boolean,
  exportText: String, printHeader: Array, multiHeader: Array, exportMethod: String,
  exportQuery: [Object, Function, String], isFormat: { type: Boolean, default: true }
})

const pageSize = 1000
const route = useRoute()
const innerLoading = ref(false)
const dicQuery = computed(() => {
  return typeof props.exportQuery === 'function' ? props.exportQuery() : props.exportQuery ?? {}
})
const formatFileName = computed(() => {
  return props.fileName ? props.fileName : `${(route.meta || {})[toI18nName('menuZhCn')] || ''}`
})
const API = computed(() => props.exportMethod === 'get' ? awaitGetAPI : awaitPostAPI)

watch(() => props.loading, () => (innerLoading.value = props.loading), { immediate: true })

const getLabel = (options = [], val, prop = {}) => {
  const label = prop.label || 'label'
  const value = prop.value || 'value'
  const opt = options.find(el => el === val || el[value] === val) || {}
  return opt[label] || val
}
const formatExportData = rows => {
  const { columns = [], isFormat, merges, multiHeader, printHeader } = props
  const header = [], fields = [], options = {}, format = {}, prop = {}, cols = []
  for (const column of columns || []) {
    if (column.export === false) continue
    if (column.hide && !column.export) continue
    header.push(column.label)
    const width = column.exportWidth || 100
    if (width < 40) cols.push(8)
    else cols.push(Math.ceil(width / 5))
    const field = column.exportField || column.field
    fields.push(field)
    if (column.props) prop[field] = column.props
    if (column.format) format[field] = column.format
    if (column.options && ['array', 'function'].includes(getTypeof(column.options))) options[field] = column.options
  }
  let data
  if (isFormat) {
    data = rows.map(el => {
      return fields.map(key => {
        if (format[key]) return format[key](el[key], el)
        if (options[key]) {
          if (['array', 'object'].includes(typeof options[key])) return getLabel(options[key], el[key], prop[key])
          else if (['function'].includes(typeof options[key])) return getLabel(options[key](el), el[key], prop[key])
        }
        return el[key]
      })
    })
  } else data = rows.map(el => fields.map(key => el[key]))
  return {
    cols: [cols], header: [header], data: [data], merges: [merges], multiHeader: multiHeader ? [multiHeader] : [],
    sheetName: ['sheet1'], fileName: formatFileName.value, printHeader
  }
}
const exportData = (rows = []) => {
  if (rows.length) exportJsonToExcel(formatExportData(rows))
  else Notify.create({ type: 'warning', icon: 'warning', message: i18n.t('NoExportData') })
  innerLoading.value = false
}
const ajaxExport = async () => {
  if (typeof dicQuery.value === 'string') return
  innerLoading.value = true
  let ajaxData = [], pageNum = 1, endLoop = false
  while (true) {
    await API.value(props.exportUrl, { ...dicQuery.value, pageSize, pageNum }, data => {
      const rows = data.rows || data || [], totals = Number(data?.total || 0)
      ajaxData.push(...rows) && pageNum++
      if (rows.length < pageSize || ajaxData.length >= totals) endLoop = true
    }, () => {
      endLoop = true
      innerLoading.value = false
    })
    if (endLoop) break
  }
  if (innerLoading.value) exportData(ajaxData)
}

const handleExport = () => {
  if (typeof dicQuery.value === 'string') return
  if (props.isStream) {
    innerLoading.value = true
    exportedStreamFile({
      dicUrl: props.exportUrl,
      fileName: formatFileName.value,
      dicMethod: props.exportMethod || 'post',
      dicQuery: { ...dicQuery.value, pageSize: '-1' },
      done: () => { innerLoading.value = false }
    })
    return
  }
  if (props.exportUrl) ajaxExport()
  else exportData(props.data)
}
</script>